package com.simons.common.http;

import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.io.IOUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpException;
import org.apache.http.NameValuePair;
import org.apache.http.ParseException;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.CookieStore;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.cookie.Cookie;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

import com.simons.common.http.utils.HttpDeleteWithBody;

import lombok.extern.log4j.Log4j2;

@Log4j2
public abstract class BaseHttpClientOper {

	private static final String DEFAULT_CHARSET = "UTF-8";

	protected CloseableHttpClient httpClient;

	protected CookieStore cookieStore;

	protected HttpClientContext localContext;

	protected static final String FILE = "file";

	public void closehttpClient() {
		IOUtils.closeQuietly(httpClient);
	}

	public void login(String url, Map<String, String> params)
			throws ClientProtocolException, IOException, URISyntaxException, HttpException {
		this.doPost(url, params);
	}

	public String doGet(String url) throws ClientProtocolException, IOException, URISyntaxException {
		HttpGet httpget = new HttpGet(url);
		CloseableHttpResponse response = httpClient.execute(httpget);

		return this.getResult(response);
	}

	/**
	 * 带头部的qet请求
	 * 
	 * @author:JSM
	 */
	public String doGetWithHeader(String url, Map<String, String> headers, Map<String, String> params)
			throws ClientProtocolException, IOException, URISyntaxException {
		if (params != null && !params.isEmpty()) {
			URIBuilder uriBuilder = new URIBuilder(url);
			Set<String> keySet = params.keySet();
			for (String key : keySet) {
				uriBuilder.addParameter(key, params.get(key));
			}
			url = uriBuilder.build().toString();
		}
		HttpGet httpget = new HttpGet(url);
		if (headers != null) {
			for (String key : headers.keySet()) {
				String value = headers.get(key);
				httpget.setHeader(key, value);
			}
		}
		CloseableHttpResponse response = httpClient.execute(httpget);

		return this.getResult(response);
	}

	/**
	 * 不带header的get请求
	 * 
	 * @author:JSM
	 */
	public String doGet(String url, Map<String, String> params)
			throws ClientProtocolException, IOException, URISyntaxException {
		if (params == null || params.isEmpty()) {
			return doGet(url);
		}
		return this.doGetWithHeader(url, null, params);
	}

	/**
	 * 不带header的post请求
	 * 
	 * @author:JSM
	 */
	public String doPost(String url, Map<String, String> params)
			throws ClientProtocolException, IOException, URISyntaxException, HttpException {
		HttpPost httpPost = new HttpPost(url);
		return this.doModify(httpPost, params);
	}

	/**
	 * 带头部的post请求
	 * 
	 * @author:JSM
	 */
	public String doPostWithHeaders(String url, Map<String, String> params, Map<String, String> headers)
			throws ClientProtocolException, IOException, URISyntaxException, HttpException {
		HttpPost httpPost = new HttpPost(url);
		if (headers != null) {
			for (String key : headers.keySet()) {
				String value = headers.get(key);
				httpPost.setHeader(key, value);
			}
		}
		return this.doModify(httpPost, params);
	}

	/**
	 * soap格式的post请求
	 * 
	 * @author:JSM
	 */
	public String doSoapPost(String url, String stringContext, Charset charset)
			throws ClientProtocolException, IOException {
		Map<String, String> headers = new HashMap<String, String>();
		headers.put("Content-Type", "application/soap+xml;charset=UTF-8");
		return this.doStringPost(url, stringContext, charset, headers);
	}

	/**
	 * string方式的post请求
	 * 
	 * @author:JSM
	 */
	public String doStringPost(String url, String stringContext, Charset charset, Map<String, String> headers)
			throws ClientProtocolException, IOException {
		HttpPost httpPost = new HttpPost(url);
		// 设置头部
		if (headers != null) {
			for (String key : headers.keySet()) {
				String value = headers.get(key);
				httpPost.setHeader(key, value);
			}
		}
		return this.doModify(httpPost, stringContext, charset);
	}

	/**
	 * 根据不同的ContentType提交请求
	 */
	public String postVariable(String url, String str, String contentType, String charset) throws Exception {
		HttpPost post = new HttpPost(url);
		StringEntity entity = new StringEntity(str, charset);
		entity.setContentType(contentType);
		entity.setContentEncoding(charset);
		post.setEntity(entity);
		CloseableHttpResponse response = httpClient.execute(post);
		return getResult(response);
	}

	public String doPut(String url, Map<String, String> params)
			throws ClientProtocolException, IOException, URISyntaxException, HttpException {
		HttpPut httpPut = new HttpPut(url);
		return this.doModify(httpPut, params);
	}

	public String doDelete(String url, Map<String, String> params)
			throws ClientProtocolException, IOException, URISyntaxException, HttpException {
		HttpDeleteWithBody httpDelete = new HttpDeleteWithBody(url);
		return this.doModify(httpDelete, params);
	}

	/**
	 * 获取请求结果
	 * 
	 * @author:JSM
	 * @date 2018年5月3日
	 * @param response
	 */
	public String getResult(CloseableHttpResponse response) throws ParseException, IOException {
		try {
			int status = response.getStatusLine().getStatusCode();
			if (status >= 200 && status < 300) {
				HttpEntity entity = response.getEntity();
				String result = entity != null ? EntityUtils.toString(entity, DEFAULT_CHARSET) : null;
				EntityUtils.consume(entity);
				return result;
			} else {
				throw new ClientProtocolException("Unexpected response status: " + status);
			}
		} finally {
			IOUtils.closeQuietly(response);
		}
	}

	public String doPostFile(String url, File file) throws ClientProtocolException, IOException {
		HttpPost httpPost = new HttpPost(url);
		return this.doModifyFile(httpPost, file);
	}

	public String doPostFileAndText(String url, File file, Map<String, String> params, Map<String, String> header)
			throws ClientProtocolException, IOException {
		HttpPost httpPost = new HttpPost(url);
		return this.doModifyOnFileAndText(httpPost, file, params, header);
	}

	/**
	 * UrlEncodedFormEntity 方式的post请求
	 * 
	 * @author:JSM
	 * @date 2018年5月3日
	 * @param requestBase
	 * @param params
	 */
	public String doModify(HttpEntityEnclosingRequestBase requestBase, Map<String, String> params)
			throws ClientProtocolException, IOException, URISyntaxException, HttpException {
		List<NameValuePair> parametersList = new ArrayList<NameValuePair>();
		if (params != null) {
			// 设置key value
			Set<String> keySet = params.keySet();
			for (String key : keySet) {
				NameValuePair parameters = new BasicNameValuePair(key, params.get(key));
				parametersList.add(parameters);
			}
		}
		// HttpEntity paramsEntity =
		// EntityBuilder.create().setParameters(parametersList).build();
		requestBase.setEntity(new UrlEncodedFormEntity(parametersList, DEFAULT_CHARSET));
		CloseableHttpResponse response = httpClient.execute(requestBase, localContext);

		final List<Cookie> cookies = cookieStore.getCookies();
		for (Cookie cookie : cookies) {
			log.info(cookie.getName() + ":" + cookie.getValue());
		}

		return getResult(response);
	}

	/**
	 * 直接返回内容的请求
	 * 
	 * @author:JSM
	 * @date 2018年5月3日
	 * @param requestBase
	 *            请求
	 * @param stringContext
	 *            文字内容
	 * @param charset
	 *            字符编码
	 */
	public String doModify(HttpEntityEnclosingRequestBase requestBase, String stringContext, Charset charset)
			throws ClientProtocolException, IOException {
		StringEntity data = new StringEntity(stringContext, charset);
		requestBase.setEntity(data);
		CloseableHttpResponse response = httpClient.execute(requestBase);
		return getResult(response);
	}

	/**
	 * 带文件的传输方式
	 * 
	 * @author:JSM
	 * @date 2018年5月3日
	 * @param requestBase
	 * @param file
	 */
	public String doModifyFile(HttpEntityEnclosingRequestBase requestBase, File file)
			throws ParseException, IOException {
		return this.doModifyOnFileAndText(requestBase, file, null, null);
	}

	/**
	 * 文件，文本都带上的请求方式
	 * 
	 * @author:JSM
	 * @date 2018年5月3日
	 * @param requestBase
	 * @param file
	 * @param params
	 * @param header
	 */
	public String doModifyOnFileAndText(HttpEntityEnclosingRequestBase requestBase, File file,
			Map<String, String> params, Map<String, String> header) throws ClientProtocolException, IOException {
		MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create();
		if (params != null) {
			for (String key : params.keySet()) {
				String value = params.get(key);
				multipartEntityBuilder.addTextBody(key, value);
			}
		}
		if (file != null) {
			multipartEntityBuilder = multipartEntityBuilder.addBinaryBody(FILE, file);
		}
		if (header != null) {
			for (String key : header.keySet()) {
				String value = header.get(key);
				requestBase.setHeader(key, value);
			}
		}
		HttpEntity httpEntity = multipartEntityBuilder.build();
		requestBase.setEntity(httpEntity);
		CloseableHttpResponse response = httpClient.execute(requestBase, localContext);
		return this.getResult(response);
	}
}
